using HotFix.Script;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using LitJson;
using EventUtils;
using UnityEngine.UI;
using UnityEngine.Networking;
using ICSharpCode.SharpZipLib.Zip;

public class DownLoadManager:MonoBehaviour
{
    public static DownLoadManager Instance;

    public static bool StrongUpdate = false;//ǿ�и��°汾

    private void Awake()
    {
        Instance = this;
    }

    private string versionUrl { get { return GameConfig.WebUrl + "version.txt?v=" + DateTime.Now.ToString("yyyymmddhhmmss"); } }
    private string localVerPath { get { return GameConfig.DataPath + "version.txt"; } }
 
  

    public IEnumerator Start(GameObject gameObject,Action callBack, Action UpdateCallback = null, Action<float> strongUpdateCallback = null)
    {
        //PlayerPrefs.DeleteAll();
        if (GameConfig.IsUpdate)
        {
            if (!File.Exists(localVerPath))
            {
                yield return StartCoroutine(OnExtractResource());
            }
            else
            {
                string outfile = localVerPath;
                string infile = "";
#if UNITY_WEBGL
                infile = GameConfig.DataPath + "version.txt";
#else
                infile = GameConfig.AppContentPath() + "version.txt";
#endif

                Version localVerson = JsonMapper.ToObject<Version>(File.ReadAllText(outfile));
                Version version;
                if (Application.platform == RuntimePlatform.Android)
                {
                    WWW www = new WWW(infile);
                    yield return www;
                    version = JsonMapper.ToObject<Version>(www.text);
                    Debug.LogError("www.text==================" + www.text);
                }
                else
                {
                    version = JsonMapper.ToObject<Version>(File.ReadAllText(infile));
                }
                Debug.LogError("version.largeVersion=============" + version.largeVersion + "===========localVerson.largeVersion==============" + localVerson.largeVersion);
                if ((version.largeVersion != localVerson.largeVersion))
                {
                    yield return StartCoroutine(OnExtractResource());
                }
                //int local_zipVersion1 = 0;
                //if (PlayerPrefs.HasKey("ZipVersion"))
                //{
                //    local_zipVersion1 = PlayerPrefs.GetInt("ZipVersion");
                //}
                //if (local_zipVersion1!= localVerson.zipVersion)
                //{
                //    yield return StartCoroutine(OnExtractResource());
                //}
            }
            StartCoroutine(CheckVersion(callBack,strongUpdateCallback, UpdateCallback));

        }
        else
        {
            //OnResourceInited();
            callBack?.Invoke();
        }
    }

    public Action<string,string, float> onDownLoad;

    IEnumerator OnExtractResource()
    {
        string dataPath = GameConfig.DataPath;  //����Ŀ¼
        string resPath = GameConfig.AppContentPath(); //��Ϸ����ԴĿ¼
        ShowMessage(null,"�����ͷ���Դ:", 0);
        if (Directory.Exists(dataPath)) Directory.Delete(dataPath, true);
        Directory.CreateDirectory(dataPath);

        string infile = resPath + "files.txt";
        string outfile = dataPath + "files.txt";
        if (File.Exists(outfile)) File.Delete(outfile);

        if (Application.platform == RuntimePlatform.Android)
        {
            WWW www = new WWW(infile);
            yield return www;
            if (www.error==null)    //�ļ�������
            {
                File.WriteAllBytes(outfile, www.bytes);
            }
        }
        else
        {
            if (File.Exists(infile))
            {
                File.Copy(infile, outfile, true);
            }
        }
        yield return new WaitForEndOfFrame();
        if (File.Exists(outfile))
        {
            //�ͷ������ļ�������Ŀ¼
            string[] files = File.ReadAllLines(outfile);
            Debug.LogError("load path:" + files.Length);
            int index = 0;
            foreach (var file in files)
            {
                string[] fs = file.Split('|');
                infile = resPath + fs[0];  //
                outfile = dataPath + fs[0];

                string dir = Path.GetDirectoryName(outfile);
                if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
                Debug.LogError("����ļ�:" + outfile);
                bool canUpdate = true;
                if (File.Exists(outfile))
                {
                    string remoteMd5 = fs[1];
                    string localMd5 = Utils.md5file(outfile);
                    canUpdate = !remoteMd5.Equals(localMd5);
                    if (canUpdate) File.Delete(outfile);
                }
                if (!canUpdate)
                {
                    continue;
                }

                if (Application.platform == RuntimePlatform.Android)
                {
                    WWW www = new WWW(infile);
                    yield return www;

                    if (www.isDone)
                    {
                        File.WriteAllBytes(outfile, www.bytes);
                    }
                    yield return 0;
                }
                else
                {
                    if (File.Exists(outfile))
                    {
                        File.Delete(outfile);
                    }

                    File.Copy(infile, outfile, true);
                }
                index++;
                ShowMessage(null,"�����ͷ���Դ:", index * 1.0f / files.Length);
                yield return new WaitForEndOfFrame();
            }
        }
        infile = resPath + "version.txt";
        outfile = dataPath + "version.txt";
        if (Application.platform == RuntimePlatform.Android|| Application.platform == RuntimePlatform.WebGLPlayer)
        {
            WWW www = new WWW(infile);
            yield return www;

            if (www.isDone)
            {
                File.WriteAllBytes(outfile, www.bytes);
            }
            yield return 0;
        }
        else File.Copy(infile, outfile, true);
    }

    public void Update()
    {
        foreach (var item in threadDic)
        {
            item.Value.OnUpdate();
        }
    }

    void ShowMessage(string fileName,string msg,float progress)
    {
        onDownLoad?.Invoke(fileName,msg, progress);
    }


    private IEnumerator CheckVersion(Action callBack,Action<float> strongUpdateCallback =null, Action UpdateCallback = null)
    {
        Debug.LogError("CheckVersion---------------------------");
        //PlayerPrefs.DeleteAll();
        ShowMessage(null,"�����Դ����:", 0);
        WWW www = new WWW(versionUrl);
        yield return www;
        if (www.error != null)
        {
            Debug.LogError(versionUrl + www.error);
            ShowMessage(null,$"�����Դ����:{www.error}", 0);
            yield return new WaitForSeconds(1f);
            StartCoroutine(CheckVersion(callBack));
        }
        else
        {
            string romateText = www.text;
            Version romateVer = JsonMapper.ToObject<Version>(romateText);
            string localVerPath = GameConfig.DataPath + "version.txt";
            Version localVer = JsonMapper.ToObject<Version>(File.ReadAllText(localVerPath));
            //Debug.LogError("=======romateVer.largeVersion===============" + romateVer.largeVersion + "=======================" + localVer.largeVersion);

            int local_zipVersion = -1;
            if (PlayerPrefs.HasKey("ZipVersion"))
            {
                local_zipVersion = PlayerPrefs.GetInt("ZipVersion");
            }
            //Debug.LogError("romateVer.largeVersion=======" + romateVer.largeVersion + "=======localVer.largeVersion=======" + localVer.largeVersion + "======localVer.zipVersion=====" + localVer.zipVersion);

            if (romateVer.largeVersion != localVer.largeVersion)
            {
                StrongUpdate = true;
                UpdateCallback?.Invoke();
               
            }
            // else if (local_zipVersion!= localVer.zipVersion)
            // {
            //     //开始下载zip
            //     Debug.LogError("开始下载=========================");
            //     //LoadingBuriedPoint loadingBuriedPoint = new LoadingBuriedPoint();g
            //     LoadingBuriedPoint.loadingBuriedPoint.OnInitData(0);
            //     StartCoroutine(DownloadZipAndUpdate("Hall", "0", strongUpdateCallback, () => {
            //         //解压zip完成
            //         LoadingBuriedPoint.loadingBuriedPoint.OnInitData(2);
            //         StartCoroutine(CheckSubGame(romateVer, () =>
            //         {
            //             Debug.LogError("�ı��ļ�====================" + localVerPath);
            //             File.WriteAllText(localVerPath, romateText);
            //             PlayerPrefs.SetInt("ZipVersion", localVer.zipVersion);
            //             callBack?.Invoke();
            //         }));
            //     }));
            // }
            else if (romateVer.smallVersion != localVer.smallVersion)
            {
                //string loaclVersionNum = "0";
                //if (PlayerPrefs.HasKey("LoaclVersion_Key"))
                //{
                //    loaclVersionNum = PlayerPrefs.GetString("LoaclVersion_Key");g
                //}
                Debug.LogError("��ȴ�������Դ");
                DownLoadGameFiles("files.txt", () =>
                {
                    Debug.LogError("�������");
                    StartCoroutine(CheckSubGame(romateVer, () =>
                    {
                        File.WriteAllText(localVerPath, romateText);
                        callBack?.Invoke();
                    }));

                    //OnResourceInited();
                  
                });
            }
            else
            {
                Debug.LogError("����Ҫ����");
                callBack?.Invoke();
            }
        }
    }

    IEnumerator CheckSubGame(Version version,Action action)
    {
        Debug.LogError("�������Ϸ����");
        if (version.moudleList!=null)
        {
            for (int i = 0; i < version.moudleList.Count; i++)
            {
                
                MoudleVersion moudleVersion = version.moudleList[i];
                Debug.LogError("�������Ϸ"+ moudleVersion.gameName);
                yield return StartCoroutine(CheckSubGameRequestFile($"{moudleVersion.gameName}.txt", (needUpdate) =>
                {
                    if (needUpdate)
                    {
                        Debug.LogError($"����Ϸ{moudleVersion.gameName}��Ҫ����");
                    
                    }
                    else
                    {
                        PlayerPrefs.SetInt(moudleVersion.gameName, version.smallVersion);
                        Debug.LogError($"����Ϸ{moudleVersion.gameName}����Ҫ����");
                    }
                }));
            }
        }
        action?.Invoke();
    }


    public void DownLoadGameFiles(string fileName,Action callBack)
    {
        StartCoroutine(RequestFile(fileName, () =>
        {
            callBack?.Invoke();
        }));
    }
    public IEnumerator RequestFile(string fileTxt, Action onFinsh)
    {
        string dataPath = GameConfig.DataPath;  //����Ŀ¼
        string url = GameConfig.WebUrl;
        string random = DateTime.Now.ToString("yyyymmddhhmmss");

        string listUrl = url + $"{fileTxt}?v=" + random;
        WWW www = new WWW(listUrl); yield return www;
        if (www.error != null)
        {
            Debug.LogError(listUrl + www.error);
            StartCoroutine(RequestFile(fileTxt, onFinsh));
            yield break;
        }
        if (!Directory.Exists(dataPath))
        {
            Directory.CreateDirectory(dataPath);
        }
        //File.WriteAllBytes(dataPath + "files.txt", www.bytes);
        string filesText = www.text;
        string[] files = filesText.Split('\n');
        Dictionary<string, RomateFileInfo> bundleDataDic = new Dictionary<string, RomateFileInfo>();
        for (int i = 0; i < files.Length; i++)
        {
            if (string.IsNullOrEmpty(files[i])) continue;
            string[] fs = files[i].Split('|');
            bundleDataDic[fs[0]] = new RomateFileInfo
            {
                name = fs[0].Trim(),
                md5 = fs[1].Trim(),
                size = long.Parse(fs[2].Trim()),
            };
        }
        StartCoroutine(UpdateRescesource(fileTxt,bundleDataDic, onFinsh));
    }
    public long allSize;
    Dictionary<string, ThreadManager> threadDic = new Dictionary<string, ThreadManager>();
    public IEnumerator UpdateRescesource(string fileName,Dictionary<string, RomateFileInfo> bundleDataDic, Action onFinsh)
    {
        string dataPath = GameConfig.DataPath;  //����Ŀ¼
        string url = GameConfig.WebUrl;
        string random = DateTime.Now.ToString("yyyymmddhhmmss");

        ShowMessage(fileName,"��������:", 0);
        if (!Directory.Exists(dataPath))
        {
            Directory.CreateDirectory(dataPath);
        }

        List<RomateFileInfo> updateFiles = new List<RomateFileInfo>();
        foreach (var item in bundleDataDic)
        {
            updateFiles.Add(item.Value);
        }

        List<DownLoadInfo> list = new List<DownLoadInfo>();
        allSize = 0;
        for (int i = 0; i < updateFiles.Count; i++)
        {
            RomateFileInfo key = updateFiles[i];
            if (string.IsNullOrEmpty(key.name)) continue;
            string f = key.name;
            string localfile = (dataPath + f).Trim();
            string path = Path.GetDirectoryName(localfile);
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            string fileUrl = url + f + "?v=" + random;
            bool canUpdate = !File.Exists(localfile);

            if (!canUpdate)
            {
                string remoteMd5 = key.md5.Trim();
                string localMd5 = Utils.md5file(localfile);
                canUpdate = !remoteMd5.Equals(localMd5);
                if (canUpdate)
                {
                    File.Delete(localfile);
                }
            }
            if (canUpdate)
            {   //����ȱ���ļ�
                list.Add(new DownLoadInfo()
                {
                    fileUrl = fileUrl,
                    localPath = localfile,
                    size = key.size,

                });
                allSize += key.size;
            }
        }
        ThreadManager threadManager = null;
        if (!threadDic.ContainsKey(fileName))
        {
            threadDic[fileName] = new ThreadManager();
        }
        threadManager = threadDic[fileName];
        threadManager.fileName = fileName;
        threadManager.allSize = allSize;
        threadManager.downSize = 0;
        if (list.Count > 0)
        {
            for (int i = 0; i < list.Count; i++)
            {
                DownLoadInfo downLoadInfo = list[i];
                Debug.Log("update path:" + downLoadInfo.fileUrl);
                BeginDownload(threadManager,downLoadInfo.fileUrl, downLoadInfo.localPath);
                while (!(IsDownOK(downLoadInfo.localPath))) { yield return new WaitForEndOfFrame(); }
            }
        }
        
        yield return new WaitForEndOfFrame();
        threadDic.Remove(fileName);
        if (onFinsh != null)
        {
            onFinsh();
        }
    }
 
 
    private static List<string> downloadFiles = new List<string>();
    bool IsDownOK(string file)
    {
        return downloadFiles.Contains(file);
    }
    void BeginDownload(ThreadManager threadManager,string url, string file)
    {     //�߳�����
        object[] param = new object[2] { url, file };
        ThreadEvent ev = new ThreadEvent();
        ev.Key = NotiConst.UPDATE_DOWNLOAD;
        ev.evParams.AddRange(param);
        threadManager.AddEvent(ev, OnThreadCompleted);   //�߳�����
    }
  
    void OnThreadCompleted(NotiData data)
    {
        switch (data.evName)
        {
            case NotiConst.UPDATE_EXTRACT:
                //
                break;
            case NotiConst.UPDATE_PROGRESS:
                ShowMessage(data.threadManager.fileName,"�����ͷ���Դ:", (float)(data.threadManager.downSize / data.threadManager.allSize));
                break;
            case NotiConst.UPDATE_DOWNLOAD:
                downloadFiles.Add(data.evParam.ToString());
                //LoadManager.Instance.ShowMessage("��������:", (float)(ThreadManager.downSize / ThreadManager.allSize));
                break;
        }
    }


    //
    public IEnumerator CheckSubGameRequestFile(string fileTxt, Action<bool> onFinsh)
    {
        string dataPath = GameConfig.DataPath;  //����Ŀ¼
        string url = GameConfig.WebUrl;
        string random = DateTime.Now.ToString("yyyymmddhhmmss");

        string listUrl = url + $"{fileTxt}?v=" + random;
        WWW www = new WWW(listUrl); yield return www;
        if (www.error != null)
        {
            Debug.Log(listUrl + www.error);
            yield return StartCoroutine(CheckSubGameRequestFile(fileTxt, onFinsh));
            yield break;
        }
        if (!Directory.Exists(dataPath))
        {
            Directory.CreateDirectory(dataPath);
        }
        //File.WriteAllBytes(dataPath + "files.txt", www.bytes);
        string filesText = www.text;
        string[] files = filesText.Split('\n');
        Dictionary<string, RomateFileInfo> bundleDataDic = new Dictionary<string, RomateFileInfo>();
        for (int i = 0; i < files.Length; i++)
        {
            if (string.IsNullOrEmpty(files[i])) continue;
            string[] fs = files[i].Split('|');
            bundleDataDic[fs[0]] = new RomateFileInfo
            {
                name = fs[0].Trim(),
                md5 = fs[1].Trim(),
                size = long.Parse(fs[2].Trim()),
            };
        }
        yield return StartCoroutine(CheckSubGameUpdateRescesource(bundleDataDic, onFinsh));
    }
   
    public IEnumerator CheckSubGameUpdateRescesource(Dictionary<string, RomateFileInfo> bundleDataDic, Action<bool> onFinsh)
    {
        string dataPath = GameConfig.DataPath;  //����Ŀ¼
        string url = GameConfig.WebUrl;
        string random = DateTime.Now.ToString("yyyymmddhhmmss");
     
        if (!Directory.Exists(dataPath))
        {
            Directory.CreateDirectory(dataPath);
        }
        List<RomateFileInfo> updateFiles = new List<RomateFileInfo>();
        foreach (var item in bundleDataDic)
        {
            updateFiles.Add(item.Value);
        }

        List<DownLoadInfo> list = new List<DownLoadInfo>();
        for (int i = 0; i < updateFiles.Count; i++)
        {
            RomateFileInfo key = updateFiles[i];
            if (string.IsNullOrEmpty(key.name)) continue;
            string f = key.name;
            string localfile = (dataPath + f).Trim();
            Debug.Log("localfile======================" + localfile);
            string path = Path.GetDirectoryName(localfile);
            Debug.Log("path======================" + path);
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            string fileUrl = url + f + "?v=" + random;
            bool canUpdate = !File.Exists(localfile);

            if (!canUpdate)
            {
                string remoteMd5 = key.md5.Trim();
                string localMd5 = Utils.md5file(localfile);
                canUpdate = !remoteMd5.Equals(localMd5);
                if (canUpdate)
                {
                    File.Delete(localfile);
                }
            }
            if (canUpdate)
            {   //����ȱ���ļ�
                list.Add(new DownLoadInfo());
                break;
            }
        }

        onFinsh?.Invoke(list.Count > 0);
        yield return 0;
    }




    /// <summary>
    /// �����ļ�
    /// </summary>
    /// <param name="gameName"></param>
    /// <param name="gameVersion"></param>
    /// <returns></returns>
    IEnumerator DownloadZipAndUpdate(string gameName, string gameVersion, Action<float> strongUpdateCallback = null, Action DownLoadcallBack=null)
    {
        string dataPath = GameConfig.DataPath;  //����Ŀ¼
       
        // ����Զ�̷������ϴ�汾�����ļ���URL
        string remoteZipFileURL = GameConfig.WebUrl + gameName + ".zip";

        // ����ZIP�ļ�
        using (UnityWebRequest downloadRequest = UnityWebRequest.Get(remoteZipFileURL))
        {
            downloadRequest.downloadHandler = new DownloadHandlerFile(Path.Combine(Application.persistentDataPath, "temp.zip"));
            downloadRequest.SendWebRequest();

            while (!downloadRequest.isDone)
            {
                float progress = downloadRequest.downloadProgress;
                Debug.Log($"{gameName} download progress: {progress:P}");
                strongUpdateCallback?.Invoke(progress);
                //image_pro.fillAmount = progress;
                //txt_pro.text = (progress * 100f).ToString("F2") + "%";
                yield return null;
            }

            if (downloadRequest.result == UnityWebRequest.Result.Success)
            {
                //下载zip完成
                //LoadingBuriedPoint loadingBuriedPoint = new LoadingBuriedPoint();
                LoadingBuriedPoint.loadingBuriedPoint.OnInitData(1);
                Debug.Log("zip download end =========="+ Application.persistentDataPath);
                string zipFilePath = Path.Combine(Application.persistentDataPath, "temp.zip");

                // ��ѹ��ZIP�ļ�
                string extractionPath = Path.Combine(Application.persistentDataPath, dataPath);
                ZipUtilitys.UnzipFile(zipFilePath, extractionPath);
                // ɾ����ʱZIP�ļ�
                File.Delete(zipFilePath);
                DownLoadcallBack?.Invoke();
                Debug.Log($"{gameName} update completed!");
            }
            else
            {
                Debug.LogError($"Error downloading {gameName} update: {downloadRequest.error}");
            }
        }
    }






}

public class DownLoadInfo
{
    public string fileUrl;
    public string localPath;
    public long size;
}

public class RomateFileInfo
{
    public string name;
    public string md5;
    public long size;
}

// ��ѹ��������
public static class ZipUtilitys
{
    public static void UnzipFile(string zipFilePath, string extractionPath)
    {

        if (!Directory.Exists(extractionPath))
            Directory.CreateDirectory(extractionPath);

        using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipFilePath)))
        {
            try
            {
                ZipEntry entry;
                //ZipConstants.DefaultCodePage = System.Text.Encoding.UTF8.CodePage;
#if !UNITY_EDITOR 
                ZipConstants.DefaultCodePage = System.Text.Encoding.UTF8.CodePage;
#endif
                while ((entry = zipStream.GetNextEntry()) != null)
                {
                    string entryName = entry.Name;
                    if (entry.IsFile)
                    {
                        string fullPath = Path.Combine(extractionPath, entryName);
                        string directory = Path.GetDirectoryName(fullPath);
                        if (!Directory.Exists(directory))
                            Directory.CreateDirectory(directory);
                        using (FileStream streamWriter = File.Create(fullPath))
                        {
                            byte[] data = new byte[2048];
                            int bytesRead;
                            while ((bytesRead = zipStream.Read(data, 0, data.Length)) > 0)
                            {
                                streamWriter.Write(data, 0, bytesRead);
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {

                Debug.LogError("==================+++++++++======" + e.Message);
            }
            
        }
    }
}
